package cn.kust.clock.service.impl;

import cn.kust.clock.mapper.LikeMapper;
import cn.kust.clock.pojo.dto.LikeDTO;
import cn.kust.clock.pojo.entity.Like;
import cn.kust.clock.repository.impl.LikeClockRedisRepository;
import cn.kust.clock.repository.impl.LikeTravelsRedisRepository;
import cn.kust.clock.service.LikeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

/**
 * @author YL
 * @data 2022/7/21 11:00
 **/
@Slf4j
@Service
public class LikeServiceImpl extends ServiceImpl<LikeMapper, Like> implements LikeService {

    @Autowired
    LikeMapper likeMapper;

    @Autowired
    LikeClockRedisRepository likeClockRedisRepository;

    @Autowired
    LikeTravelsRedisRepository likeTravelsRedisRepository;

    public static final int LikeClockType = 1;
    public static final int LikeTravelsType = 2;

    /**
     * 获取点赞总数
     * @param type 点赞类型
     * @param typeId 作品id
     * @return 点赞总数
     */
    @Override
    public Integer getLikeCountByTypeAndTypeId(Integer type, Long typeId) {
        log.info("进入点赞统计Service");
        //首先去缓存查询是否有对应点赞
        if (type == null) {
            //抛出异常
            log.debug("type == null");
        } else if (type == LikeClockType) {
            //是打卡点赞
            log.debug("根据id（{}）获取打卡点赞数……", typeId);
            // 从repository中调用方法，根据id获取缓存的数据
            // 判断缓存中是否存在与此id对应的key
            boolean exists = likeClockRedisRepository.exists(typeId);
            if (exists) {
                // 有：表示明确的存入过某数据，此数据可能是有效数据，也可能是null
                // -- 判断此key对应的数据是否为null
                Integer cacheResult = likeClockRedisRepository.getCountById(typeId);
                if (cacheResult == null) {
                    // -- 是：表示明确的存入了null值，则此id对应的数据确实不存在，则抛出异常
                    log.warn("在缓存中存在此id（{}）对应的Key，却是null值，则抛出异常", typeId);
                    // throw new ServiceException(State.ERR_LikeNum_NOT_FOUND, "获取点赞失败，尝试访问的数据不存在！");
                } else {
                    // -- 否：表示明确的存入了有效数据，则返回此数据即可
                    return cacheResult;
                }
            }

            // 缓存中没有此id匹配的数据
            // 从mapper中调用方法，根据type和typeId获取数据库的数据
            log.debug("没有命中缓存，则从数据库查询数据……");
            Integer dbResult = likeMapper.getLikeCountByTypeAndTypeId(type, typeId);
            // 判断从数据库中获取的结果是否为null
            if (dbResult == null) {
                // 是：数据库也没有此数据，先向缓存中写入错误数据，再抛出异常
                log.warn("数据库中也无此数据（id={}），先向缓存中写入错误数据", typeId);
                likeClockRedisRepository.saveEmptyValue(typeId);
                log.warn("抛出异常");
//                throw new ServiceException(State.ERR_TypeId_NOT_FOUND, "获取类别详情失败，尝试访问的数据不存在！");
            }

            // 将从数据库中查询到的结果存入到缓存中
            log.debug("已经从数据库查询到匹配的数据，将数据存入缓存……");
            likeClockRedisRepository.save(dbResult, typeId);
            // 返回查询结果
            log.debug("返回查询到数据：{}", dbResult);
            return dbResult;

        } else if (type == LikeTravelsType) {
            //是游记点赞
            log.debug("根据id（{}）获取游记点赞数……", typeId);
            // 从repository中调用方法，根据id获取缓存的数据
            // 判断缓存中是否存在与此id对应的key
            boolean exists = likeTravelsRedisRepository.exists(typeId);

            if (exists) {
                // 有：表示明确的存入过某数据，此数据可能是有效数据，也可能是null
                // -- 判断此key对应的数据是否为null
                Integer cacheResult = likeTravelsRedisRepository.getCountById(typeId);
                if (cacheResult == null) {
                    // -- 是：表示明确的存入了null值，则此id对应的数据确实不存在，则抛出异常
                    log.warn("在缓存中存在此id（{}）对应的Key，却是null值，则抛出异常", typeId);
                    // throw new ServiceException(State.ERR_LikeNum_NOT_FOUND, "获取点赞失败，尝试访问的数据不存在！");
                } else {
                    // -- 否：表示明确的存入了有效数据，则返回此数据即可
                    return cacheResult;
                }
            }

            // 缓存中没有此id匹配的数据
            // 从mapper中调用方法，根据type和typeId获取数据库的数据
            log.debug("没有命中缓存，则从数据库查询数据……");
            Integer dbResult = likeMapper.getLikeCountByTypeAndTypeId(type, typeId);
            // 判断从数据库中获取的结果是否为null
            if (dbResult == null) {
                // 是：数据库也没有此数据，先向缓存中写入错误数据，再抛出异常
                log.warn("数据库中也无此数据（id={}），先向缓存中写入错误数据", typeId);
                likeTravelsRedisRepository.saveEmptyValue(typeId);
                log.warn("抛出异常");
//                throw new ServiceException(State.ERR_TypeId_NOT_FOUND, "获取类别详情失败，尝试访问的数据不存在！");
            }

            // 将从数据库中查询到的结果存入到缓存中
            log.debug("已经从数据库查询到匹配的数据，将数据存入缓存……");
            likeTravelsRedisRepository.save(dbResult, typeId);
            // 返回查询结果
            log.debug("返回查询到数据：{}", dbResult);
            return dbResult;

        }
        //直接返回
        return likeMapper.getLikeCountByTypeAndTypeId(type, typeId);
    }

    /**
     * 根据传入类型id查询热门贴
     * @param type id类型
     * @param pageNum 页码 第一页就传一
     * @return 热门id列表
     */
    @Override
    public List<Long> selectHotOfHighLike(Integer type, Integer pageNum) {
        log.info("进入查询热门贴Service");
        return likeMapper.selectHotOfHighLike(type, (pageNum-1)*100);
    }


    /**
     * 根据传入的type_id, type, user_id 添加一条点赞记录
     * @param likeDTO 点赞详细DTO类
     * @return 受影响行数
     */
    @Override
    public Integer insertLikeHistory(LikeDTO likeDTO) {
        log.info("进入添加一条点赞记录Service");
        Like like = new Like();
        BeanUtils.copyProperties(likeDTO, like);
        like.setStatus(1);
        like.setGmtCreate(LocalDateTime.now());

        //如果点赞总数缓存存在，修改点赞总数加一
        if (likeDTO.getType() == LikeClockType) {
            boolean exists = likeClockRedisRepository.exists(likeDTO.getTypeId());
            if (exists) {
                // 有：表示明确的存入过某数据，此数据可能是有效数据，也可能是null
                // -- 判断此key对应的数据是否为null
                Integer cacheResult = likeClockRedisRepository.getCountById(likeDTO.getTypeId());
                if (cacheResult == null) {
                    // -- 是：表示明确的存入了null值，则此id对应的数据确实不存在，则抛出异常
                    log.warn("在缓存中存在此id（{}）对应的Key，却是null值，则抛出异常", likeDTO.getTypeId());
                } else {
                    // -- 否：表示明确的存入了有效数据，则点赞总数加一
                    likeClockRedisRepository.save(cacheResult+1,likeDTO.getTypeId());
                }
            }
        } else if (likeDTO.getType() == LikeTravelsType) {
            boolean exists = likeTravelsRedisRepository.exists(likeDTO.getTypeId());
            if (exists) {
                // 有：表示明确的存入过某数据，此数据可能是有效数据，也可能是null
                // -- 判断此key对应的数据是否为null
                Integer cacheResult = likeTravelsRedisRepository.getCountById(likeDTO.getTypeId());
                if (cacheResult == null) {
                    // -- 是：表示明确的存入了null值，则此id对应的数据确实不存在，则抛出异常
                    log.warn("在缓存中存在此id（{}）对应的Key，却是null值，则抛出异常", likeDTO.getTypeId());
                } else {
                    // -- 否：表示明确的存入了有效数据，则点赞总数加一
                    likeTravelsRedisRepository.save(cacheResult+1,likeDTO.getTypeId());
                }
            }
        }

        return likeMapper.insert(like);
    }

    /**
     * 删除一条点赞记录，即status设为0
     * @param id 点赞主键id
     * @return 受影响行数
     */
    @Override
    public Integer deleteLikeHistoryById(Long id) {
        log.info("进入删除点赞记录Service");
        //传入1，到update就变为0
        return likeMapper.deleteById(id);
    }


    /**
     * 根据点赞id与点赞状态修改点赞状态
     * @param likeDTO 包括type typeId userId status
     * @return 受影响行数
     */
    @Override
    public Integer updateLikeHistoryByLikeDTO(LikeDTO likeDTO){
        log.info("进入修改点赞记录Service");
        //先判断是否存在此条数据，存在修改，不存在插入
        Integer count = likeMapper.selectByLikeDTO(likeDTO);
        if (count == 0) {
            return insertLikeHistory(likeDTO);
        }
//        likeDTO.setStatus(likeDTO.getStatus() == 1 ? 0 : 1);
        if (likeDTO.getType() == LikeClockType) {
            boolean exists = likeClockRedisRepository.exists(likeDTO.getTypeId());
            if (exists) {
                log.info("缓存中存在数据");
                // 有：表示明确的存入过某数据，此数据可能是有效数据，也可能是null
                // -- 判断此key对应的数据是否为null
                Integer cacheResult = likeClockRedisRepository.getCountById(likeDTO.getTypeId());
                if (cacheResult == null) {
                    // -- 是：表示明确的存入了null值，则此id对应的数据确实不存在，则抛出异常
                    log.warn("在缓存中存在此id（{}）对应的Key，却是null值，则抛出异常", likeDTO.getTypeId());
                } else {
                    log.info("改变缓存中存在数据");
                    // -- 否：表示明确的存入了有效数据，则点赞总数改变
                    if (likeDTO.getStatus() == 1) {
                        cacheResult += 1;
                    }else{
                        cacheResult -= 1;
                    }
                    likeClockRedisRepository.save(cacheResult,likeDTO.getTypeId());
                }
            }
        } else if (likeDTO.getType() == LikeTravelsType) {
            boolean exists = likeTravelsRedisRepository.exists(likeDTO.getTypeId());
            if (exists) {
                log.info("缓存中存在数据");
                // 有：表示明确的存入过某数据，此数据可能是有效数据，也可能是null
                // -- 判断此key对应的数据是否为null
                Integer cacheResult = likeTravelsRedisRepository.getCountById(likeDTO.getTypeId());
                if (cacheResult == null) {
                    // -- 是：表示明确的存入了null值，则此id对应的数据确实不存在，则抛出异常
                    log.warn("在缓存中存在此id（{}）对应的Key，却是null值，则抛出异常", likeDTO.getTypeId());
                } else {
                    log.info("改变缓存中存在数据");
                    // -- 否：表示明确的存入了有效数据，则点赞总数改变
                    if (likeDTO.getStatus() == 1) {
                        cacheResult += 1;
                    }else{
                        cacheResult -= 1;
                    }
                    likeTravelsRedisRepository.save(cacheResult,likeDTO.getTypeId());
                }
            }
        }

        return likeMapper.updateLikeHistoryByLikeDTO(likeDTO);
    }

}
